using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Security;
using System.Text.RegularExpressions;
using mesoBoard.Data.Repositories;
using mesoBoard.Data;
using mesoBoard.Web.Providers;
using mesoBoard.Web;
using mesoBoard.Web.Core;
using mesoBoard.Web.ViewModels;
using mesoBoard.Services;

namespace mesoBoard.Web.Controllers
{
    public partial class AuthController : mesoBoardController
    {
        public AuthController()
        {
        }

        public ActionResult ActivateUser(string uname, string code)
        {
            ViewData["BreadCrumb"] = "Activate Account";

            if (Repositories.Users.ActivateUser(uname, code))
            {
                SetSuccess("Your account has been activated. Please use the information you registered with to login.");
                User TheUser = Repositories.Users.GetUser(uname);
                Emailing.WelcomeEmail(TheUser);
                return RedirectToAction("Login");
            }
            else
            {
                SetError("The activation link you provided was invalid. Please use the link provided in the activation email");
                return View();
            }
        }

        [HttpGet]
        public ActionResult Register()
        {
            ViewData["BreadCrumb"] = "Register";
            return View();
        }

        [CaptchaVerify("Captcha", "myCaptcha")]
        [HttpPost]
        public ActionResult Register(string Pass, string ConfirmPass, bool Terms, User TheUser)
        {
            int PassMin =  SiteConfig.PasswordMin.ToInt();
            int UsernameMin =  SiteConfig.UsernameMin.ToInt();
            int UsernameMax =  SiteConfig.UsernameMax.ToInt();

            ViewData["BreadCrumb"] = "Register";
            if(string.IsNullOrEmpty(TheUser.Username))
                ModelState.AddModelError("Username", "Enter a username");
            else if (Repositories.Users.UserExists(TheUser.Username))
                ModelState.AddModelError("Username", "Username already taken");
            else if (TheUser.Username.Length > UsernameMax || TheUser.Username.Length < UsernameMin)
                ModelState.AddModelError("Username", "Username length must be between " + UsernameMin + " and " + UsernameMax + " characters long");

            if (!Terms)
                ModelState.AddModelError("Terms", "You must agree to the terms and conditions");
            
            if(string.IsNullOrEmpty(TheUser.Email))
                ModelState.AddModelError("Email", "Enter an email address");
            else if (Repositories.Users.EmailInUse(TheUser.Email))
                ModelState.AddModelError("Email", "Email is already in use by another user");
            else if (!RegEx.IsValidEmail(TheUser.Email))
                ModelState.AddModelError("Email", "A valid email address is required");

            if (string.IsNullOrEmpty(Pass))
                ModelState.AddModelError("Pass", "Enter a password");
            else if (Pass.Length < PassMin)
                ModelState.AddModelError("NewPassword", "Minimum password length is " + PassMin + " characters");
            else if(Pass != ConfirmPass)
                ModelState.AddModelError("ConfirmPass", "Confirm password must match password");

            if (ModelState.IsValid)
            {
                TheUser.Password = Pass;
                mbServices.Users.Register(TheUser);
                string ActivationType =  SiteConfig.AccountActivation.Value;
                
                string CreateSucess = "User <b>" + TheUser.Username +
                    "</b> was created.";

                if (ActivationType == "Email")
                    CreateSucess += " An activation email has been sent to <b>" +
                       TheUser.Email + "</b> with details on how to activate the account";
                else if (ActivationType == "Admin")
                    CreateSucess += " Admin activation is required. You will not be able to login until an admin activates your account";

                TempData["Success"] = CreateSucess;
                if (ActivationType == "Email")
                {
                    string confirm_url =  SiteConfig.BoardURL.Value + Url.Action("ActivateUser", "Auth", new { uname = TheUser.Username, code = TheUser.ActivationCode });
                    Emailing.Registration(TheUser, confirm_url);
                }
                return RedirectToAction("Login");
            }
            else
            {
                SetError("Invalid Registration Information");
                return View();
            }
        }

        [HttpGet]
        public ActionResult Login(string ReturnURL)
        {
            ViewData["BreadCrumb"] = "Login";
            if (!string.IsNullOrEmpty(ReturnURL))
                SetNotice("You must login to access this page");
            return View();
        }

        [HttpPost]
        public ActionResult Login(string Username, string Password, string ReturnURL, bool RememberMe)
        {
            ViewData["BreadCrumb"] = "Login";
            if (mbServices.Users.UserExists(Username))
            {
                User TheUser = mbServices.Users.GetUser(Username);
                if (mbServices.Users.ValidatePassword(TheUser, Password))
                {
                    ReturnURL = ReturnURL ?? Url.Action("Index", "Board");
                    mbServices.Users.LoginRoutine(TheUser, Request.UserHostAddress);
                    FormsAuthentication.SetAuthCookie(TheUser.UserID.ToString(), RememberMe);

                    SetSuccess("Successfully Logged In");
                    return Redirect(ReturnURL);
                }
                else
                {
                    if (!string.IsNullOrEmpty(TheUser.ActivationCode))
                    {
                        TagBuilder link = new TagBuilder("a");
                        link.Attributes.Add("href", Url.Action("ResendActivationCode", new {UserID = TheUser.UserID}));
                        link.InnerHtml = "resend the activation email";
                        SetNotice("<b>" + TheUser.Username + "</b>'s account has not been activated yet. Click here to " + link.ToString());
                    }
                    SetError("Invalid Login Credentials");
                    return View();
                }
            }
            else
            {
                SetError("Invalid Username");
                return View();
            }
        }

        public ActionResult Logout()
        {
            if (User.Identity.IsAuthenticated)
            {
                mbServices.Users.LogoutRoutine(int.Parse(User.Identity.Name));
                FormsAuthentication.SignOut();
            }
            SetSuccess("Successfully Logged out");
            return RedirectToAction("Index", "Board");
        }

        [HttpGet]
        public ActionResult ForgotPassword()
        {
            ViewData["BreadCrumb"] = "Forgot Password";
            return View();
        }

        [HttpPost]
        public ActionResult ForgotPassword(string UsernameOrEmail)
        {
            ViewData["BreadCrumb"] = "Forgot Password";
            User TheUser = mbServices.Users.GetUser(UsernameOrEmail);
            if (TheUser != null)
            {
                string token = mbServices.Users.RequestPasswordReset(TheUser.UserID);
                string reset_url = Url.Action("ResetPassword", "Auth", new { token = token });
                Emailing.PasswordResetRequest(TheUser, reset_url);
                SetSuccess("A password reset request link has been sent to the associated email address. Please check your email to reset your password");
                return RedirectToAction("Login");
            }
            else
            {
                SetError("Email/Username was not found");
                return View();
            }
        }

        [HttpGet]
        public ActionResult ResetPassword(string token)
        {
            if (mbServices.Users.ValidatePasswordResetRequest(token))
            {
                User TheUser = mbServices.Users.GetUser(int.Parse(token.Split('-')[0]));
                string newPass = mbServices.Users.ResetPassword(TheUser.UserID);
                Emailing.PasswordChanged(TheUser, newPass);
                mbServices.Users.DeletePasswordResetRequest(TheUser.UserID);
                SetSuccess("Password reset, an email as been set to the associated email address of the account");
                return RedirectToAction("Login");
            }
            else
            {
                SetError("Invalid reset password token. The token is incorrect or expired. Please issue another reset request");
                return RedirectToAction("ForgotPassword");
            }
        }

        [HttpGet]
        public ActionResult ResendActivationCode()
        {
            ViewData["BreadCrumb"] = "Resend Activation Code";
            return View();
        }

        [HttpPost]
        public ActionResult ResendActivationCode(string UsernameOrEmail)
        {
            ViewData["BreadCrumb"] = "Resend Activation Code";
            User TheUser = mbServices.Users.GetUser(UsernameOrEmail);
            if (TheUser != null)
            {
                if (string.IsNullOrEmpty(TheUser.ActivationCode))
                    SetNotice("This account is already active. Visit the Password Reminder page if you have forgotten your password.");
                else
                {
                    string confirm_url = SiteConfig.BoardURL.Value + Url.Action("ActivateUser", "Auth", new { uname = TheUser.Username, code = TheUser.ActivationCode });
                    Emailing.ResendActivationCode(TheUser, confirm_url);

                    string success = string.Format(
                        "An email has been sent to <b>{0}</b> with the activation link for this account",
                        TheUser.Email
                        );

                    SetSuccess(success);
                }
                return RedirectToAction("Login");
            }
            else
            {
                SetError("Email/Username was not found");
                return View();
            }
        }
    }
}
